l
<!--
 * @Author: Liz.Zheng
 * @Date: 2021-11-09 20:04:59
 * @LastEditTime: 2022-11-28 16:04:13
 * @LastEditors: 郑亚莉 zhengyali@shequ.life
 * @Description: 添加、编辑角色
 * @Motto: Write the code. Change the world.
-->

<template>
  <div>
    <a-drawer
      :title="title"
      :maskClosable="false"
      :visible="visible"
      :destroyOnClose="true"
      :width="800"
      :body-style="{ paddingBottom: '50px' }"
      @close="closeModal"
      class="role-drawer"
    >
      <a-form layout="vertical">
        <a-form-item label="角色名称" v-bind="validateInfos.name">
          <a-input placeholder="请输入角色名称" v-model:value="modelRef.name" />
        </a-form-item>
        <a-form-item label="角色描述" v-bind="validateInfos.title">
          <a-input
            placeholder="请输入角色描述"
            v-model:value="modelRef.title"
          />
        </a-form-item>
        <a-form-item class="label-w-100">
          <template #label>
            <a-row
              type="flex"
              justify="space-between"
              align="middle"
              style="width: 100%"
            >
              <a-col>角色权限</a-col>
              <a-col v-if="!loading">
                <a-checkbox
                  v-model:checked="allCheckedMenu"
                  @change="handleAllCheckedChange"
                >
                  全选
                </a-checkbox>
              </a-col>
            </a-row>
          </template>
          <section v-if="loading" class="text-center mt-50">
            <a-spin />
          </section>
          <section class="menu-list" v-else>
            <a-tree
              checkable
              :tree-data="menuList"
              :defaultExpandAll="true"
              :checkedKeys="menuCheckedKeys"
              :fieldNames="{
                children: 'menu_list',
                title: 'name',
                key: 'onlyKey',
              }"
              @check="handleMenuCheck"
            >
              <template #title="{dataRef}">
                <a-row type="flex" align="middle" justify="space-between">
                  <a-col>
                    {{dataRef.name}}
                  </a-col>
                </a-row>
              </template>
            </a-tree>
          </section>

        </a-form-item>
      </a-form>
      <div class="drawer-footer">
        <a-button class="mr-10" @click.prevent="closeModal">取消</a-button>
        <a-button
          type="primary"
          :loading="submitLoading"
          :disabled="disabledSubmit"
          @click.prevent="onSubmit"
        >
          保存
        </a-button>
      </div>
    </a-drawer>
  </div>
</template>

<script>
import {
  defineComponent,
  computed,
  ref,
  reactive,
  watch,
  nextTick,
  toRaw,
  toRefs,
} from "vue";
import { Form, message } from "ant-design-vue";
import request from "../../../../common/utils/request";
import utils from "../../../../common/utils/utils";
import _ from "lodash";
const useForm = Form.useForm;
const defaultCheckedAlias = ['personalInfo', 'changeCompany'];
export default defineComponent({
  name: "CompanyEditRole",
  components: {
  },
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    id: {
      type: [String, Number],
      default: 0,
    },
  },
  setup(props, context) {
    /**
     * @description: 标题显示
     */
    const title = computed(() => {
      return props.id ? "编辑角色" : "添加角色";
    });

    const state = reactive({
      allCheckedMenu: false,  // 菜单全选
      submitLoading: false, // 提交loading
      menuList: [],
      loading: false,
      menuCheckedKeys: [], // 全选的数据
      halfMenuCheck: [], // 半选的数据
      disabledSubmit: false,
      menuSubmitResult: false,
      resultCheckedMenuKey: [],
      defaultCheckedDis: [], // 默认勾选 且 禁用的数据
      allMenuLength: 0,
    });

    /**
     * @description: 表单字段
     */

    const modelRef = reactive({
      name: "",
      title: "",
      module: "",
    });

    /**
     * @description: 验证规则
     */
    const rulesRef = reactive({
      name: [{ required: true, message: "角色名称为必填项" }],
    });

    /**
     * @description: 创建表单
     */
    const { resetFields, validate, validateInfos } = useForm(
      modelRef,
      rulesRef
    );


    const getOnlyOneKey = (list, init) => {
      let level = 0;
      let _length = 0;
      const set = new Set(state.menuCheckedKeys);
      const setChildrenOnlyOne = (arr, level, parentKey) => {
        level += 1;
        arr.map((v) => {
          if (init) {
            _length ++;
          }
          v.onlyKey = v.id + '_' + level;
          v.parentKey = parentKey;
          v.class = `level-tree-${level}`;
          if (defaultCheckedAlias.includes(v?.alias)) {
            v.disabled = true;
            v.onlyKey = v.onlyKey + '-defaultCheck-';
            if (init) {
              state.defaultCheckedDis.push(v);
              set.add(v.onlyKey)
            }
          } else {
            v.disabled = false;
          }
          if (v?.alias == 'applications') {
            v.class = 'applications-level level-tree-1';
          }
          if (v.menu_list && v.menu_list.length) {
            setChildrenOnlyOne(v.menu_list, level, v.onlyKey + '&' + v.parentKey)
          } else {
            let actionArr = [];
            // 处理action的情况
            Object.keys(v?.action || {}).forEach((key) => {
              if (v.action[key]?.length) {
                v.action[key] = v.action[key].map((action) => {
                  if (init) {
                    _length ++;
                  }
                  action.onlyKey = v.onlyKey + '-action-' + key + '-' + action.label;
                  action.parentKey = v.onlyKey + '&' + v.parentKey;
                  actionArr.push(action);
                  return action;
                })
              }
            })
            Object.keys(v?.action || {}).forEach((key) => {
              if (v.action[key]?.length) {
                v.action[key] = v.action[key].map((action) => {
                  action.actionArr = actionArr;
                  action.class = 'actions-level';
                  return action;
                })
              }
            })
            let _menuAction = [];
            Object.keys(v?.action || {}).forEach((key) => {
              if (v.action[key]?.length) {
                _menuAction = _menuAction.concat(v.action[key])
              }
            })
            v.menu_list = _.cloneDeep(_menuAction);
            v.isAction = true;
          }
          return v
        })
      };
      setChildrenOnlyOne(list, level, 0);
      if (init) {
        state.allMenuLength = _length - 1;
        state.menuCheckedKeys = Array.from(set);
      }
      return list
    };

    const getRoleMenu = () => {
      state.loading = true;
      request.get("/org", "/role/getOrgMenu").then((res) => {
        state.menuList = getOnlyOneKey(res.menuList, true);
        if (props.id) {
          getRoleDetail();
        } else {
          state.loading = false;
          state.allCheckedMenu = false;
        }
      });
    };

    // 选择菜单则下面所有内容都将被勾选
    const setAllMenuCheck = (list, checked) => {
      const set = new Set(state.menuCheckedKeys);
      const setHalf = new Set(state.halfMenuCheck);
      const setMenuChildrenAndActionCheck = (arr, checked) => {
        arr.forEach((current) => {
          if (checked) {
            set.add(current.onlyKey)
          } else {
            if (!defaultCheckedAlias.includes(current.alias)) {
              set.delete(current.onlyKey)
            } else {
              let parentKey = String(current?.parentKey).split('&');
              parentKey = parentKey.filter((v) => v !== '0')
              parentKey.forEach((v) => {
                setHalf.add(v)
              })
            }
          }
          if (current.menu_list && current.menu_list.length) {
            setMenuChildrenAndActionCheck(current.menu_list, checked);
          }
        })
      };
      setMenuChildrenAndActionCheck(list, checked);
      state.menuCheckedKeys = Array.from(set);
      state.halfMenuCheck = Array.from(setHalf);
    };
    const handleAllCheckedChange = () => {
      state.menuSubmitResult = false;
      setAllMenuCheck(state.menuList, state.allCheckedMenu);
    };

    const handleMenuCheck = (checkedKeys, e) => {
      // 处理中不给保存
      state.disabledSubmit = true;
      state.menuSubmitResult = false;
      let _checkedKeys = _.cloneDeep(checkedKeys);
      let _checkNodes =  _.cloneDeep(e.checkedNodes);
      let needFilter = false;
      let fatherIds = e?.halfCheckedKeys || [];
      _checkNodes.forEach((v) => {
        if (v.onlyKey.indexOf('defaultCheck') !== -1) {
          let parentKey = String(v?.parentKey).split('&');
          parentKey = parentKey.filter((v) => v !== '0')
          fatherIds = ([...new Set(fatherIds.concat(parentKey))]);
        }
      })
      if (!e.checked) {
        // 取消选中 如果是查看 取消所有的兄弟节点的选中
        let key = e.node.onlyKey;
        let keyArr = key.split('-');
        if (keyArr[keyArr.length - 1] === 'list') {
          // 取消勾选查看 // 则取消所有的 操作项
          e.checkedNodes.forEach((v) => {
            if (v.onlyKey.indexOf('action') !== -1) {
              // 是操作项
              let keys = v.onlyKey.split('-');
              if (keyArr[0] === keys[0]) {
                needFilter = true;
                _checkedKeys = _checkedKeys.filter((item) => item!== v.onlyKey);
                _checkNodes = _checkNodes.filter((item) => item.onlyKey !== v.onlyKey);
              }
            }
          })
        }
      } else  {
        // 选中 如果选择的是操作项 且 权限里有查看 且 查看没有被选择 则手动勾选查看项
        let key = e.node.onlyKey;
        let keyArr = key.split('-');
        if (key.indexOf('action') !== -1 && keyArr[keyArr.length - 1] !== 'list') {
          // 选择的是非查看的操作项
          let actionArr = e.node?.actionArr;
          let haveList = false;
          let listKey = '';
          actionArr.forEach((item) => {
            let keys = item.onlyKey.split('-');
            if (keys[keys.length - 1] === 'list') {
              haveList = true
              listKey = item.onlyKey;
            }
          })
          if (haveList && listKey) {
            _checkedKeys.push(listKey);
          }
        }
      }
      if (needFilter) {
        // 需要过滤半选数据
        if (_checkNodes.length) {
          _checkNodes.forEach((item) => {
            let parentKey = String(item?.parentKey).split('&');
            fatherIds = ([...new Set(fatherIds.concat(parentKey))]);
          })
          // 过滤掉一级的 和 全选的
          fatherIds = fatherIds.filter((v) => v !== '0' && !_checkedKeys.includes(v))
        }
      }
      state.menuCheckedKeys = ([...new Set(_checkedKeys)]);
      state.halfMenuCheck = ([...new Set(fatherIds)]);
      state.allCheckedMenu = (state.menuCheckedKeys.concat(state.halfMenuCheck)?.length || 0) === state.allMenuLength;
      state.disabledSubmit = false;
    };

    const getCheckedList = (list, result) => {
      if (!list.length) return []
      list.forEach((item) => {
        let node = {...item, menu_list: []};
        if (item.checked) {
          // 选中的
          result.push(node);
          state.resultCheckedMenuKey.push(item.onlyKey);
        }
        if (item?.menu_list?.length) {
          getCheckedList(item.menu_list, node.menu_list)
        }
      })
      return result
    }

    const setEditDetailChecked = (allList, settingList = []) => {
      let checkedList = [];
      getCheckedList(settingList, checkedList);
      const set = new Set(state.menuCheckedKeys);
      let _allCheck = true;
      const setCheckedFromEdit = (defaultList, checkedArr) => {
        defaultList.forEach((item) => {
          const result = checkedArr.find((item2) => item2.onlyKey == item.onlyKey);
          if (result) {
            if (result?.menu_list?.length > 0) {
              if (item?.menu_list?.length) {
                setCheckedFromEdit(item.menu_list, result.menu_list);
              }
            } else {
              // 最子菜单选中
              // 如果是app 需判断是不是第一层级的 不是第一级 且 不是隐藏菜单
              if (!item?.menu_list?.length) {
                // 确保是最后一层
                set.add(item.onlyKey)
              }
            }
          } else {
            _allCheck = false;
            if (item?.menu_list?.length) {
              setCheckedFromEdit(item.menu_list, []);
            }
            if (defaultCheckedAlias.includes(item.alias)) {
              set.add(item.onlyKey)
            }
          }
        })
      };
      // 此时set 为 所有层级里面最底层的keys 集合
      setCheckedFromEdit(allList, checkedList)
      state.menuCheckedKeys = Array.from(set);
      state.allCheckedMenu = _allCheck;
    };

    /**
     * @description: 获取角色详情
     */
    const getRoleDetail = () => {
      state.disabledSubmit = true;
      state.menuSubmitResult = true;
      request
        .get("/org", "/department/rolesDetail", { role_id: props.id })
        .then((res) => {
          const { list } = res;
          modelRef.name = list.name;
          modelRef.title = list.title;
          let _menuList = getOnlyOneKey(list.menu_list);
          setEditDetailChecked(state.menuList, _menuList);
          state.loading = false;
          state.disabledSubmit = false;
        }).catch(() => {
        state.loading = false;
        state.disabledSubmit = false;
      });
    };

    /**
     * @description: 触发关闭
     */
    const closeModal = () => {
      context.emit("closeEdit");
    };


    const getCheckedMenu = (arr, checked) => {
      let resultMenu = [];
      let resultMethod = [];
      let virtualAppId = [];
      let checkedAppIds = [];
      const loopMenu = (menu) => {
        menu.map((v) => {
          v.checked = checked.includes(v.onlyKey);
          if (v.checked) {
            resultMenu.push(v);
            if (v?.app_id) {
              if (v?.is_unreal) {
                virtualAppId.push(v.app_id);
              } else {
                checkedAppIds.push(v.app_id)
              }
            }
          }
          if (v.menu_list?.length) {
            if (!v.isAction) {
              loopMenu(v.menu_list);
            } else {
              // 是操作项
              Object.keys(v.action).forEach((key) => {
                if (v.action[key]?.length) {
                  v.action[key] = v.action[key].map((action) => {
                    action.checked = checked.includes(action.onlyKey);
                    if (action.checked) {
                      resultMethod.push(action.classMethod)
                    }
                    delete action.actionArr;
                    return action;
                  })
                }
              })
              v.menu_list = [];
              delete v.isAction;
            }
          }
          return v
        })
      }
      loopMenu(arr);
      return {
        menu: resultMenu,
        classMethod: resultMethod,
        unreal_app_module: virtualAppId,
        checkedAppIds,
      }
    };

    /**
     * @description: 提交表单
     */
    const getSubmitParams = () => {
      return new Promise((resolve) => {
        // 扁平化菜单权限 按钮权限直接赋值
        let _menuList = _.cloneDeep(state.menuList);
        // 修改checked 值 且 改变数据
        let checkedKeyList = [];
        if (state.menuSubmitResult) {
          // 这块是防止 个人设置 选中 父没选中 兼容老数据
          let fatherIds = [];
          let defaultChecked = [];
          state.defaultCheckedDis.forEach((v) => {
            let parentKey = String(v?.parentKey).split('&');
            parentKey = parentKey.filter((v) => v !== '0')
            fatherIds = ([...new Set(fatherIds.concat(parentKey))]);
            defaultChecked.push(v?.onlyKey);
          });
          let checkedIds = fatherIds.concat(defaultChecked);  // 默认勾选且禁用的数据 包含父级别
          // 这块是防止 个人设置 选中 父没选中 兼容老数据
          checkedKeyList = _.cloneDeep([...new Set(state.resultCheckedMenuKey.concat(checkedIds))]);
        } else {
          checkedKeyList = ([...new Set(state.menuCheckedKeys.concat(state.halfMenuCheck))]) // 包含全选 和 半选
        }
        let result = getCheckedMenu(_menuList, checkedKeyList);
        resolve(result);
      });
    };

    const onSubmit = () => {
      validate()
        .then(() => {
          state.submitLoading = true;
          getSubmitParams().then((module) => {
            let params = {
              ...modelRef,
              module: {
                menu: module.menu,
                classMethod: module.classMethod,
              },
              unreal_app_module: module.unreal_app_module,
              app_module: module.checkedAppIds,
              needMsg: true,
            };
            const success = (res) => {
              message.success(res.msg || "操作成功");
              context.emit("success");
              state.submitLoading = false;
            };
            if (props.id) {
              params.role_id = props.id;
              request
                .put("/org", "/department/role", params)
                .then((res) => success(res)).catch(() => {
                  state.submitLoading = false;
              });
            } else {
              request
                .post("/org", "/department/role", params)
                .then((res) => success(res)).catch(() => {
                state.submitLoading = false;
              });
            }
          });
        })
        .catch((err) => {
          console.log("error", err);
        });
    };

    /**
     * @description: 初始化
     */
    const init = () => {
      // if (props.id) {
      //   getRoleDetail();
      // } else {
      getRoleMenu();
      // }
    };

    const reset = () => {
      state.allCheckedMenu = false;
      state.submitLoading = false;
      state.menuList = [];
      state.loading = false;
      state.menuCheckedKeys = [];
      state.halfMenuCheck = [];
      state.disabledSubmit = false;
      state.menuSubmitResult = false;
      state.resultCheckedMenuKey = [];
      state.defaultCheckedDis = [];
      state.allMenuLength = 0;
    };

    watch(
      () => props.visible,
      (val) => {
        if (val) {
          init();
        } else {
          resetFields();
          reset();
        }
      }
    );

    return {
      title,
      validateInfos,
      modelRef,
      ...toRefs(state),
      resetFields,
      closeModal,
      onSubmit,
      handleAllCheckedChange,
      handleMenuCheck,
    };
  },
});
</script>

<style lang="less" scoped>
.role-drawer {
  overflow: hidden;
  .menu-list {
    height: calc(~"100vh - 380px");
    overflow: hidden auto;
    .menu-item {
      .top-menu {
        height: 40px;
        line-height: 40px;
        background: #f7f7f7;
        padding: 0 10px;
        margin-top: 20px;
        color: rgba(0, 0, 0, 0.8);
      }
      &:deep(.sub-menu-container) {
        padding: 10px 0;
        border-top: 1px solid #f7f7f7;
      }
      &:deep(.sub-menu) {
        height: 40px;
        line-height: 40px;
      }
      .menu-action {
        height: 30px;
        line-height: 30px;
        margin-bottom: 10px;
      }
    }
  }
}
:deep(.label-w-100 > .ant-form-item-label > label) {
  width: 100%;
}
// 新版antdV3 样式
:deep(.ant-tree-list-holder-inner) {
  flex-direction: row!important;
  flex-wrap: wrap!important;
}
:deep(.ant-tree-treenode) {
  width: 100%;
  padding: 5px 0!important;
}
:deep(.actions-level) {
  width: fit-content!important;
}
:deep(.level-tree-1) {
  height: 40px!important;
  line-height: 40px!important;
  background: #f7f7f7;
  color: rgba(0, 0, 0, 0.8);
  align-items: center!important;
  padding: 0!important;
  .ant-tree-checkbox {
    margin:  0 8px 0 0;
  }
  .ant-tree-switcher-icon {
    margin-top: 14px;
  }
}

:deep(.level-tree-1) {
  height: 40px!important;
  line-height: 40px!important;
  background: #f7f7f7;
  color: rgba(0, 0, 0, 0.8);
  align-items: center!important;
  padding: 0!important;
  .ant-tree-checkbox {
    margin:  0 8px 0 0;
  }
  .ant-tree-switcher-icon {
    margin-top: 14px;
  }
}

:deep(.level-tree-2) {
  padding: 10px 0!important;
  border-top: 1px solid #f7f7f7;
}

:deep(.applications-level) {
  display: flex;
  .ant-tree-node-content-wrapper {
    flex: 1;
  }
  .ant-tree-title {
    display: inline-block;
    width: 100%;
  }
}

:deep(.ant-tree-treenode-motion) {
  display: none!important;
}
:deep(.ant-tree-node-selected) {
  background-color: initial!important;
}
:deep(.ant-tree-node-content-wrapper) {
  cursor: default!important;
}
</style>
